package com.naiterui.ehp.bs.patient.service.impl;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.naiterui.ehp.bp.domain.Patient;

import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Transactional;

import com.naiterui.ehp.bp.utils.biz.NameUtils;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bs.patient.dao.IPatientDao;
import com.naiterui.ehp.bs.patient.dao.mongo.ApPatientDocumentDao;
import com.naiterui.ehp.bs.patient.exception.ExceptionCodes;
import com.naiterui.ehp.bs.patient.prodocl.MDrink;
import com.naiterui.ehp.bs.patient.prodocl.MFamilyDisease;
import com.naiterui.ehp.bs.patient.prodocl.MPatientDocument;
import com.naiterui.ehp.bs.patient.prodocl.MSelectOrOthers;
import com.naiterui.ehp.bs.patient.prodocl.MSmoke;
import com.naiterui.ehp.bs.patient.service.IPatientDocumentService;
import com.naiterui.ehp.bs.patient.utils.LimitValueConfig;
import com.naiterui.ehp.bs.patient.utils.exception.PatientBusinessException;

/**
 * <患者档案业务实现>
 *
 * @version 2015年7月20日 上午11:43:19 by Amber
 * @see <IPatientDocumentService>
 */
@Service
public class ApPatientDocumentServiceImpl implements IPatientDocumentService {

    private static final Logger LOGGER = LoggerFactory.getLogger(ApPatientDocumentServiceImpl.class);

    @Autowired
    private ApPatientDocumentDao apPatientDocumentDao;

    @Autowired
    private IPatientDao patientDao;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MPatientDocument saveDocument(Long patientId, MPatientDocument document) throws PatientBusinessException {
        // 校验输入
        try {
            this.validatePatientDocument(document);
        } catch (PatientBusinessException be) {
            throw be;
        } catch (Exception e) {
            LOGGER.info("校验参数异常", e);
            throw new PatientBusinessException(ExceptionCodes.PARAM_ERROR, e);
        }

        Patient patient = this.patientDao.get(patientId);
        // 患者不存在
        if (patient == null) {
            LOGGER.error("--------------- save document error. patient not exist. patientId {}", patientId);
            throw new PatientBusinessException(ExceptionCodes.PATIENT_NOT_EXIST);
        }
        if (patient.getAccountStatus() != 0) { // 账户异常
            LOGGER.error("--------------- save document error. patient account status wrong. patientId {}", patientId);
            throw new PatientBusinessException(ExceptionCodes.PATIENT_ACCOUNT_ERROR);
        }
        // 查询旧数据
        MPatientDocument oldDocument = this.apPatientDocumentDao.queryDocument(patientId);
        String date = DateUtil.formatDate(new Date(), DateUtil.DATE_TIME_FORMAT);
        if (oldDocument != null) {
            // 修改旧数据
            oldDocument.update(document);
            oldDocument.setChangeAt(date);
            oldDocument.setChangeBy("patient:" + patientId);
            this.apPatientDocumentDao.save(oldDocument);
        } else {
            // 新建档案，绑定患者
            document.setPatientId(patientId);
            document.setCreateAt(date);
            document.setCreateBy("patient:" + patientId);
            document.setChangeAt(date);
            document.setChangeBy("patient:" + patientId);
            this.apPatientDocumentDao.save(document);
        }

        return this.apPatientDocumentDao.queryDocument(patientId);
    }

    /**
     * 校验患者输入参数
     *
     * @param document
     *
     * @Description
     * @History 2017年6月26日 by wangchuan
     * @since V2.8.0
     */
    private void validatePatientDocument(MPatientDocument document) throws PatientBusinessException {
        if (document == null) {
            return;
        }

        // 身高
        Integer height = document.getHeight();
        if (height != null) {
            if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_PATIENT_HEIGHT, String.valueOf(height))) {
                LOGGER.info("身高输入长度超限:{}", height);
                throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
            }
        }

        // 体重
        Integer weight = document.getWeight();
        if (weight != null) {
            if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_PATIENT_WEIGHT, String.valueOf(weight))) {
                LOGGER.info("体重输入长度超限:{}", weight);
                throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
            }
        }

        // 药物过敏史
        MSelectOrOthers medicAllergys = document.getMedicAllergys();
        if (medicAllergys != null) {
            String others = medicAllergys.getOthers();
            if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_DISEASE_OTHERS, others)) {
                LOGGER.info("过敏药物，填写内容长度超过限制");
                throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
            }

            // 表情符号校验
            if (!this.validateEmoji(others)) {
                LOGGER.info("过敏药物，包含表情符号");
                throw new PatientBusinessException(ExceptionCodes.EMOJI_ERROR);
            }
        }

        // 既往病史
        MSelectOrOthers pastDiseases = document.getPastDiseases();
        if (pastDiseases != null) {
            String others = pastDiseases.getOthers();
            if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_DISEASE_OTHERS, others)) {
                LOGGER.info("过往病史，填写内容长度超过限制");
                throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
            }

            // 表情符号校验
            if (!this.validateEmoji(others)) {
                LOGGER.info("过往病史，包含表情符号");
                throw new PatientBusinessException(ExceptionCodes.EMOJI_ERROR);
            }
        }

        // 家族病史
        List<MFamilyDisease> familyDiseases = document.getFamilyDiseases();
        if (familyDiseases != null && familyDiseases.size() > 0) {
            for (MFamilyDisease familyDisease : familyDiseases) {
                if (familyDisease == null) {
                    continue;
                }
                MSelectOrOthers disease = familyDisease.getDisease();
                if (disease == null) {
                    continue;
                }
                String others = disease.getOthers();
                if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_DISEASE_OTHERS, others)) {
                    LOGGER.info("家族病史，填写内容长度超过限制");
                    throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
                }

                // 表情符号校验
                if (!this.validateEmoji(others)) {
                    LOGGER.info("家族病史，包含表情符号");
                    throw new PatientBusinessException(ExceptionCodes.EMOJI_ERROR);
                }
            }
        }

        // 遗传病
        MSelectOrOthers hereditaryDiseases = document.getHereditaryDiseases();
        if (hereditaryDiseases != null) {
            String others = hereditaryDiseases.getOthers();
            if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_DISEASE_OTHERS, others)) {
                LOGGER.info("遗传病，填写内容长度超过限制");
                throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
            }

            // 表情符号校验
            if (!this.validateEmoji(others)) {
                LOGGER.info("遗传病，包含表情符号");
                throw new PatientBusinessException(ExceptionCodes.EMOJI_ERROR);
            }
        }

        MSmoke smoke = document.getSmoke();
        // 吸烟，校验吸烟数量
        if (smoke != null && String.valueOf(MSmoke.SMOKE_STATUS_YES).equals(smoke.getStatus())) {
            // 日吸烟数量（支）
            String perdayNum = smoke.getPerdayNum();
            // 吸烟开始年龄（岁）
            String smokeStart = smoke.getSmokeStart();

            // 日吸烟量1-100
            int perdayNumInt = Integer.parseInt(perdayNum);
            if (perdayNumInt < 1 || perdayNumInt > 100) {
                LOGGER.info("日吸烟量值太大！");
                throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_SMOKE_PERDAY_INVALID);
            }

            // 开始吸烟年龄1~99
            int smokeInt = Integer.parseInt(smokeStart);
            if (smokeInt < 1 || smokeInt > 99) {
                LOGGER.info("吸烟开始年龄值太大！");
                throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_SMOKE_AGE_INVALID);
            }
        }

        MDrink drink = document.getDrink();
        if (drink != null) {
            Integer frequency = drink.getFrequency();
            // 偶尔、每天饮酒
            if (frequency != null && (MDrink.DRINK_STATUS_SOMETIME == frequency || MDrink.DRINK_STATUS_EVERYDAY == frequency)) {
                String perdayNum = drink.getPerdayNum();
                if (StringUtils.isBlank(perdayNum)) {
                    LOGGER.info("日饮酒量为空");
                    throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_DRINK_PERDAY_INVALID);
                }
                if (perdayNum.length() < 1 || perdayNum.length() > 2) {
                    LOGGER.info("日饮酒量填写不正确");
                    throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_DRINK_PERDAY_INVALID);
                }

                String drinkStart = drink.getDrinkStart();
                if (StringUtils.isBlank(drinkStart)) {
                    LOGGER.info("开始饮酒年龄为空");
                    throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_DRINK_START_AGE_INVALID);
                }
                if (drinkStart.length() < 1 || drinkStart.length() > 3) {
                    LOGGER.info("开始饮酒年龄不正确");
                    throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_DRINK_START_AGE_INVALID);
                }

                // 已戒酒
                if (String.valueOf(MDrink.DRINK_STATUS_NO).equals(drink.getDrinkStatus())) {
                    String stopAge = drink.getStopAge();
                    if (StringUtils.isBlank(stopAge)) {
                        LOGGER.info("戒酒年龄为空");
                        throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_DRINK_STOP_AGE_INVALID);
                    }
                    if (stopAge.length() < 1 || stopAge.length() > 3) {
                        LOGGER.info("戒酒年龄不正确");
                        throw new PatientBusinessException(ExceptionCodes.PATIENT_DISEASE_DRINK_STOP_AGE_INVALID);
                    }
                }

                MSelectOrOthers wines = drink.getWines();
                // 其他酒类
                if (wines != null) {
                    String others = wines.getOthers();
                    if (!LimitValueConfig.validateLimit(LimitValueConfig.LIMIT_WINES_OTHERS, others)) {
                        LOGGER.info("其他酒类，填写内容长度超过限制");
                        throw new PatientBusinessException(ExceptionCodes.INPUT_TOO_LONG);
                    }

                    // 表情符号校验
                    if (!this.validateEmoji(others)) {
                        LOGGER.info("其他酒类，包含表情符号");
                        throw new PatientBusinessException(ExceptionCodes.EMOJI_ERROR);
                    }
                }
            }
        }
    }

    @Override
    public MPatientDocument getDocument(Long patientId) throws PatientBusinessException {
        Patient patient = this.patientDao.get(patientId);
        // 患者不存在
        if (patient == null) {
            LOGGER.error("--------------- save document error. patient not exist. patientId {}", patientId);
            throw new PatientBusinessException(ExceptionCodes.PATIENT_NOT_EXIST);
        }
        if (patient.getAccountStatus() != 0) { // 账户异常
            LOGGER.error("--------------- save document error. patient account status wrong. patientId {}", patientId);
            throw new PatientBusinessException(ExceptionCodes.PATIENT_ACCOUNT_ERROR);
        }
        MPatientDocument patientDocument = this.apPatientDocumentDao.queryDocument(patientId);
        return patientDocument == null ? new MPatientDocument() : patientDocument;
    }

    /**
     * 校验表情符号
     *
     * @param params
     *
     * @return
     *
     * @Description true校验通过 false校验未通过
     * @History 2017年6月15日 by wangchuan
     * @since v2.8
     */
    private boolean validateEmoji(String... params) {
        if (params == null || params.length <= 0) {
            return true;
        }
        for (String content : params) {
            if (StringUtils.isNotEmpty(content) && !content.matches(NameUtils.VALIDATE_REGEX_OTHERS)) {
                return false;
            }
        }
        return true;
    }
}
